package org.teach.study.aigo.Oyh_filecut;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.mutable.MutableLong;
import org.quincy.rock.core.util.IOUtil;
import org.quincy.rock.core.util.RockUtil;
import org.quincy.rock.core.util.StringUtil;
import org.springframework.context.support.MessageSourceAccessor;

/**
 * Hello world!
 *
 */
/**
 * <b>FastSlice。</b>
 * <p><b>详细说明：</b></p>
 * <!-- 在此添加详细说明 -->
 * 无。
 * 
 * @version 1.0
 * @author Nymphet
 * @since 1.0
 */
public class FastSlice {
	//MSA 是用于访问本地化消息源的常量。
	//locale 是表示默认语言环境的静态变量。
	//charset编码
	private static final MessageSourceAccessor MSA = RockUtil.getMessageSourceAccessor("i8n.fileslice-resources");
	private static Locale locale = Locale.getDefault();
	private static Charset charset=StringUtil.UTF_8;
	
	
	/**
	 * <b>main。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 主函数 菜单 -->
	 * 无。
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		// 创建 Options 对象
		Options options = createOptions();

 		// 添加 -h 选项
		options.addOption("h", "help", false, "打印帮助信息");

		// 创建 CommandLineParser 对象
		CommandLineParser parser = new DefaultParser();

		try {
			// 解析命令行参数
			CommandLine cmd = parser.parse(options, args);
			if (cmd.hasOption("locale")) {
				String langString = cmd.getOptionValue("locale");
				locale = LocaleUtils.toLocale(langString);

			}
			if (cmd.hasOption("encode")) {
				String encode = cmd.getOptionValue("encode");
				charset = Charset.forName(encode);

			}
			// 检查是否指定了 -h 参数
			if (cmd.hasOption("h")) {
				//OYH_Help();
				printHelp(options,System.out);
			}
			// 检查是否指定了 -cp 参数
			else if (cmd.hasOption("cp")) {
				String dirString=cmd.getOptionValue("cp");
				File file=new File(dirString);
					if(!file.isDirectory()) 
						throw new SliceException(getMessage("error.cmdline.dir.notfound", file.getAbsolutePath()));
						String cpString=Oyh_classpath(file);
						System.out.println(cpString);
					
			}
			else if (cmd.hasOption("test")) {
			int rowCount = Integer.parseInt(cmd.getOptionValue("test"));
            String fileName = "test.csv"; //也可以通过命令行参数获取生成的文件名，这里简单写死了
            createTestFile(rowCount, fileName);
			 }else {
					String arg[] = cmd.getArgs();
					if (arg.length == 0) {
						throw new SliceException(getMessage("error.cmdline.datafile.miss"));
					}
					File file = new File(arg[0]);
					if (!file.isFile()) {
						throw new SliceException(getMessage("error.cmdline.file.notfound", file.getAbsolutePath()));

					}
					
					if (cmd.hasOption('n')) {// 检查是否指定了 -n 参数
						long count = getRowCount(file);
						System.out.println(count);
					} else if (cmd.hasOption("show")) {
						MutableLong from = new MutableLong(1);
						MutableLong to = new MutableLong(-1);
						StringUtil.split(cmd.getOptionValue("show"), new char[] { '-', ',' }, (index, ele) -> {
							if (index == 0) {
								from.setValue(Long.valueOf(ele.toString()));

							} else {
								to.setValue(Long.valueOf(ele.toString()));
							}
						});
						if (to.longValue() == -1) {
							to.setValue(from.longValue());
							from.setValue(1);
						}
						if (from.longValue() < 1) {
							from.setValue(1);
						}
						if (to.longValue() < 1) {
							to.setValue(1);
						}
							long rowCount = showDateRow(file, from.longValue() - 1, to.longValue());
							System.out.println(getMessage("cmdline.show.done", rowCount));
						
					}else if(cmd.hasOption("cut")) {
						MutableLong from = new MutableLong(1);
						MutableLong to = new MutableLong(-1);
						StringUtil.split(cmd.getOptionValue("show"), new char[] { '-', ',' }, (index, ele) -> {
							if (index == 0) {
								from.setValue(Long.valueOf(ele.toString()));

							} else {
								to.setValue(Long.valueOf(ele.toString()));
							}
						});
						if (to.longValue() == -1) {
							to.setValue(from.longValue());
							from.setValue(1);
						}
						if (from.longValue() < 1) {
							from.setValue(1);
						}
						if (to.longValue() < 1) {
							to.setValue(1);
						}
						if(args.length==1) {
							throw new SliceException(getMessage("error.cmdline.destfile.miss"));
							
						}
		                // 根据需求进行相应操作，切分数据文件从 from 行到 to 行
		                System.out.println("执行 -cut 操作，从 " + from + " 到 " + to);
		            }
					else if (cmd.hasOption("split")) {
		                int splitSize = Integer.parseInt(cmd.getOptionValue("split"));
		                // 根据需求进行相应操作，将大文件拆分成每个小文件包含 splitSize 行的数据
		                System.out.println("执行 -split 操作，每个小文件包含 " + splitSize + " 行数据");
		            }
				}

		} catch (ParseException e) {
			System.out.println("命令行参数解析失败：" + e.getMessage());
		}
	}

	/**
	 * <b>createOptions。</b>
	 * <p><b>详细说明：</b></p>
	 * <!--  添加选项... -->
	 * 无。
	 * @return
	 */
	private static Options createOptions() {
  
        Options options = new Options();
        options.addOption("h", "help", false, getMessage("help.cmdline.option.help"));
        options.addOption("n", "rowcount", false, getMessage("help.cmdline.option.rowcount"));
        options.addOption("show", true, getMessage("help.cmdline.option.show"));
        options.addOption("locale", true, getMessage("help.cmdline.option.locale"));
        options.addOption("encode", true, getMessage("help.cmdline.option.encode"));
        options.addOption("cp", "classpath", true, getMessage("help.cmdline.option.classpath"));
        options.addOption("cut", true, getMessage("help.cmdline.option.cut"));
        options.addOption("split", true, getMessage("help.cmdline.option.split"));
        options.addOption("test", true, getMessage("help.cmdline.option.test"));
        return options;
        
  
    }
	
	
	/**
	 * <b>getMessage。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param key
	 * @param args
	 * @return
	 */
	public static String getMessage(String key, Object... args)
	{
		return MSA.getMessage(key, args, locale);
	}

	
	/**
	 *  <b>OYH_Help。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 自己研究的一个帮助写法 -->
	 * 无。
	 */
	public static void OYH_Help() {
		// 配置文件路径
		String configFilePath = "/i8n/fileslice-resources.properties";

		try {
			InputStream input = FastSlice.class.getResourceAsStream(configFilePath);
			//设定语言为UTF-8再读取
			InputStreamReader myReader1 = new InputStreamReader(input, StandardCharsets.UTF_8);
			// 加载属性文件
			Properties properties = new Properties();
			properties.load(myReader1);
			// 创建一个 LinkedHashMap 来保存帮助信息
			LinkedHashMap<String, String> helpInfo = new LinkedHashMap<>();

			// 获取以 "help." 开头的键值对
			for (String key : properties.stringPropertyNames()) {
			    if (key.startsWith("help.cmdline.option.")) {
			        helpInfo.put(key, properties.getProperty(key));
			    }
			}
			/*help.usage.title=用法：
			help.usage.header=这是一个将大文本文件分割成多个小文本文件的工具。 \n其中选项包括：
					help.usage.footer=有关详细信息，请参考帮助文档。
				*/
			
			// 打印帮助信息（乱序）
			for (Map.Entry<String, String> entry : helpInfo.entrySet()) {
			    System.out.println(entry.getValue());
			}

			
	   
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	
	
	/**
	 * <b>实现-h，跟着老师的帮助写法</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 标准的帮助写法 -->
	 * 无。
	 * @param options
	 * @param out
	 */
	private static void printHelp(Options options, PrintStream out)
	{
		out.print(getMessage("help.usage.title"));
		out.println("fastslice [] [] []");
		out.println(getMessage("help.usage.header"));
		Option opts[] = (Option[])options.getOptions().toArray(new Option[0]);
		int count = opts.length;
		StringBuilder sbs[] = new StringBuilder[count];
		int maxLen = 0;
		for (int i = 0; i < count; i++)
		{
			Option opt = opts[i];
			StringBuilder sb = new StringBuilder();
			sb.append(" -");
			sb.append(opt.getOpt());
			if (opt.hasLongOpt())
			{
				sb.append(',');
				sb.append("--");
				sb.append(opt.getLongOpt());
			}
			if (opt.hasArg())
			{
				sb.append(' ');
				sb.append("<arg>");
			}
			maxLen = Math.max(maxLen, sb.length());
			sbs[i] = sb;
		}

		maxLen += 3;
		for (int i = 0; i < count; i++)
		{
			StringBuilder sb = sbs[i];
			sb.append(StringUtil.repeat(' ', maxLen - sb.length()));
			sb.append(opts[i].getDescription());
			out.println(sb.toString());
		}

		out.println(getMessage("help.usage.footer"));
	}
	
	
	/**
	 * <b>实现-test</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 创建测试文件 -->
	 * 无。
	 * @param rowCount
	 * @param fileName
	 */
	private static void createTestFile	(int rowCount, String fileName){
	    try (FileWriter writer = new FileWriter(fileName)) {
	        // 写入 CSV 文件头部
	        writer.append("Header1,Header2,Header3\n");
	        
	        // 生成指定行数的测试数据
	        for (int i = 0; i < rowCount; i++) {
	            String dataRow = "Value1_" + i + ",Value2_" + i + ",Value3_" + i + "\n";
	            writer.append(dataRow);
	        }
	        
	        System.out.println(rowCount + " 行测试数据已生成到 " + fileName);
	        
	    } catch (IOException e) {
	        System.out.println("生成测试数据时发生错误：" + e.getMessage());
	    }
	}


	/**
	 * <b>实现-show。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 */
	public static void Oyh_show(String fileName, int rowCount) {
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            int count = 0;

            while ((line = reader.readLine()) != null && count < rowCount) {
                System.out.println(line);
                count++;
            }
        } catch (IOException e) {
            System.err.println("读取文件出错：" + e.getMessage());
        }
    }

	
	/**
	 * <b>显示数据文件</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param file
	 * @param fromIndex
	 * @param toIndex
	 * @return
	 * @throws IOException
	 */
	public static long showDateRow(File file, long fromIndex, long toIndex) throws IOException {
	    InputStream in = FileUtils.openInputStream(file);  // 打开文件输入流
	    try {
	        BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));  // 创建字符缓冲读取器，指定字符集
	        long index = 0;  // 定义变量 index，表示当前行的索引
	        String line;  // 定义变量 line，用于存储读取的每一行内容
	        while ((line = reader.readLine()) != null && index < toIndex) {  // 循环读取每一行，直到达到 toIndex 或遇到文件末尾
	            if (index++ < fromIndex)  // 如果当前行小于 fromIndex，则继续下一轮循环
	                continue;
	            System.out.println(line);  // 打印当前行内容
	        }
	        return index - fromIndex;  // 返回实际显示的行数
	    } finally {
	        IOUtil.closeQuietly(in);  // 关闭输入流
	    }
	}


	/**
	 * <b>获取文件行数</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static long getRowCount(File file) throws IOException {
		// 打开文件输入流并读取文件内容
		InputStream in = FileUtils.openInputStream(file);

		try {
			// 创建字符流读取器，并指定字符编码方式
			BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));

			long index = 0; // 记录行数的变量

			// 循环读取文件中的每一行，直到达到文件末尾
			while (reader.readLine() != null) {
				index++; // 每读取一行，行数加一
			}

			return index; // 返回文件的行数
		} finally {
			IOUtil.closeQuietly(in); // 在文件读取完成或发生异常后关闭输入流
		}
	}

	/**
	 * <b>实现 -cp 根据指定文件夹下的jar文件输出类路径。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param lib_dir
	 * @return
	 */
	public static String Oyh_classpath(File lib_dir) {
		StringBuilder sb =new StringBuilder("CLASSPATH=%CLASSPATH%");
		for(File jar :lib_dir.listFiles((dir,name)->FilenameUtils.isExtension(name, "jar"))) {
			sb.append(";%LIB_DIR%\\");
			sb.append(jar.getName());
			
		}
		sb.append("\n");
		return sb.toString();
	}
	
	/**
	 * <b>实现_cut。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param f1原文件
	 * @param f2目标文件
	 * @param l1起始行
	 * @param l2结束行
	 */
	public static void Oyh_cut(File f1, File f2, long l1, long l2) {
        try (BufferedReader reader = new BufferedReader(new FileReader(f1));
             BufferedWriter writer = new BufferedWriter(new FileWriter(f2))) {
            // 读取数据行的计数器
            long lineCount = 0;
            String line;

            // 从开始处切分出一部分数据文件，从 l1 行到 l2 行（包括 l2 行）
            while ((line = reader.readLine()) != null) {
                lineCount++;

                if (lineCount >= l1 && lineCount <= l2) {
                    // 将符合条件的数据行写入目标文件
                    writer.write(line);
                    writer.newLine();
                }

                if (lineCount > l2) {
                    // 已经达到指定切分的数据行数，结束读取
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
	
	/**
	 * <b>实现_split。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param f1 原文件
	 * @param f2  目录
	 * @param row 行数
	 */
	public static void Oyh_split(File f1, File f2, int row) {
        try (BufferedReader reader = new BufferedReader(new FileReader(f1))) {
            // 读取数据行的计数器
            int lineCount = 0;
            String line;

            // 小文件计数器
            int fileCount = 0;
            // 当前小文件的目标文件名
            String fileName = f2.getName().substring(0, f2.getName().lastIndexOf("."));

            // 存储当前小文件的数据行
            List<String> lines = new ArrayList<>();

            while ((line = reader.readLine()) != null) {
                lineCount++;
                lines.add(line);

                if (lineCount == row) {
                    // 达到指定的数据行数，创建新的小文件并写入数据
                    createAndWriteFile(fileName + "_" + fileCount + ".txt", lines);

                    // 重置数据行计数器和集合
                    lineCount = 0;
                    lines.clear();

                    // 增加小文件计数器
                    fileCount++;
                }
            }

            // 处理剩余的数据行，如果有的话
            if (!lines.isEmpty()) {
                // 创建新的小文件并写入数据
                createAndWriteFile(fileName + "_" + fileCount + ".txt", lines);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
	
	/**
	 * <b>创建并写入新的小文件</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param fileName
	 * @param lines
	 * @throws IOException
	 */
	private static void createAndWriteFile(String fileName, List<String> lines) throws IOException {
        File file = new File(fileName);

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            for (String line : lines) {
                writer.write(line);
                writer.newLine();
            }
        }
    }

}